package com.yang.job.admin.infra.job;

import com.yang.job.admin.domain.enums.JobExecuteStrategyEnum;
import com.yang.job.admin.infra.job.request.YangJobSubmitParam;
import com.yang.job.admin.infra.job.thread.YangJobThreadFactory;

import java.util.Map;
import java.util.concurrent.*;

public class YangJobManager {
    private ScheduledExecutorService scheduledExecutorService;

    private Map<String, ScheduledFuture> jobId2ScheduleFutureMap = new ConcurrentHashMap<>();

    private YangJobManager(ScheduledExecutorService scheduledExecutorService) {
        this.scheduledExecutorService = scheduledExecutorService;
    }

    public void submitJob(YangJobSubmitParam yangJobSubmitParam) {
        Integer jobId = yangJobSubmitParam.getJobId();
        if (jobId == null) {
            throw new RuntimeException("缺少任务标识=========");
        }
        ScheduledFuture scheduledFuture = jobId2ScheduleFutureMap.get(jobId.toString());
        if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
            // jobId存在对应的任务
            return;
        }

        JobExecuteStrategyEnum jobExecuteStrategy = yangJobSubmitParam.getJobExecuteStrategy();
        if (jobExecuteStrategy == null) {
            throw new RuntimeException("缺少执行策略=========");
        }

        if (jobExecuteStrategy == JobExecuteStrategyEnum.IMMEDIATE_EXECUTE) {
            yangJobSubmitParam.getRunnable().run();
            return;
        }
        scheduledFuture = scheduleJob(yangJobSubmitParam);
        jobId2ScheduleFutureMap.put(jobId.toString(), scheduledFuture);
    }

    public void cancelJob(Integer jobId) {
        if (jobId == null) {
            return;
        }
        ScheduledFuture scheduledFuture = jobId2ScheduleFutureMap.get(jobId.toString());
        if (scheduledFuture == null) {
            return;
        }
        if (!scheduledFuture.isCancelled()) {
            scheduledFuture.cancel(true);
        }
        jobId2ScheduleFutureMap.remove(jobId.toString());
    }

    private ScheduledFuture scheduleJob(YangJobSubmitParam yangJobSubmitParam) {
        Runnable runnable = yangJobSubmitParam.getRunnable();
        Integer initialDelay = yangJobSubmitParam.getInitialDelay();
        Integer period = yangJobSubmitParam.getPeriod();
        JobExecuteStrategyEnum jobExecuteStrategy = yangJobSubmitParam.getJobExecuteStrategy();
        switch (jobExecuteStrategy) {
            case ONCE:
                return scheduledExecutorService.schedule(runnable, initialDelay, TimeUnit.SECONDS);
            case WITH_FIXED_DELAY:
                return scheduledExecutorService.scheduleWithFixedDelay(runnable, initialDelay, period, TimeUnit.SECONDS);
            case WITH_FIXED_RATE:
                return scheduledExecutorService.scheduleAtFixedRate(runnable, initialDelay, period, TimeUnit.SECONDS);
        }
        throw new RuntimeException("执行策略有误===========");
    }

    public void shutdown() {
        if (this.scheduledExecutorService == null) {
            return;
        }
        if (this.scheduledExecutorService.isShutdown()) {
            return;
        }
        scheduledExecutorService.shutdown();
        try {
            if (!scheduledExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {
                scheduledExecutorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static class YangJobManagerBuilder {
        private ThreadFactory threadFactory;

        private ScheduledExecutorService scheduledExecutorService;

        public YangJobManagerBuilder() {
        }

        public YangJobManagerBuilder setThreadFactory(ThreadFactory threadFactory) {
            this.threadFactory = threadFactory;
            return this;
        }

        public YangJobManagerBuilder setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
            this.scheduledExecutorService = scheduledExecutorService;
            return this;
        }

        public YangJobManager build() {
            if (this.threadFactory == null) {
                this.threadFactory = new YangJobThreadFactory("yang");
            }
            if (this.scheduledExecutorService == null) {
                this.scheduledExecutorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),
                        this.threadFactory);
            } else {
                if (this.scheduledExecutorService instanceof ScheduledThreadPoolExecutor) {
                    ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = (ScheduledThreadPoolExecutor) this.scheduledExecutorService;
                    scheduledThreadPoolExecutor.setThreadFactory(this.threadFactory);
                }
            }
            return new YangJobManager(this.scheduledExecutorService);
        }
    }
}

